package com.example.demo;

import java.io.IOException;
import java.io.InputStream;
import java.net.InetSocketAddress;
import java.net.ServerSocket;
import java.net.Socket;
import java.nio.ByteBuffer;
import java.nio.channels.*;
import java.util.Iterator;

/**
 * @author liuhe
 * @date 2020/08/10
 */
public class IOExample {
    public static void main(String[] args) throws IOException {
//        ioMethod();
        nioMethod();
        return;
    }

    private static void nioMethod() throws IOException {
        NioSocketDemo nioSocketDemo = new NioSocketDemo();
        nioSocketDemo.initServer(10087);
        nioSocketDemo.listenSelector();
    }

    private static void ioMethod() throws IOException {
        ServerSocket serverSocket = new ServerSocket(10086);
        while (true) {
            // 获取socket套接字
            Socket socket = serverSocket.accept();// 阻塞点1，等待客户端连接
            System.out.println("有新客户端连接");

            InputStream is = socket.getInputStream();
            byte[] b = new byte[1024];
            while (true) {
                int data = is.read(b); // 阻塞点2，等待数据就绪
                if (data != -1) {
                    String s = new String(b, 0, data);
                    System.out.println(s);
                } else {
                    break;
                }
            }
        }
    }

    static class NioSocketDemo {
        private Selector selector;

        private void initServer(int port) throws IOException {
            ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
            serverSocketChannel.configureBlocking(false);// 非阻塞
            serverSocketChannel.socket().bind(new InetSocketAddress(port));
            this.selector = Selector.open(); // 通道选择器（管理器）
            serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT); // 监听连接事件
            System.out.println("服务启动...");
        }

        public void listenSelector() throws IOException {
            // 轮询监听selector
            while (true) {
                // 等待客户连接，select模型，多路复用
                this.selector.select();
                Iterator<SelectionKey> iterator = this.selector.selectedKeys().iterator();
                while (iterator.hasNext()) {
                    SelectionKey key = iterator.next();
                    iterator.remove();
                    // 处理请求
                    handler(key);
                }
            }
        }

        /**
         * 处理客户端请求
         */
        private void handler(SelectionKey key) throws IOException {
            if (key.isAcceptable()) {
                // 处理客户端连接请求事件
                ServerSocketChannel serverChannel = (ServerSocketChannel) key.channel();
                SocketChannel socketChannel = serverChannel.accept();
                socketChannel.configureBlocking(false);
                // 接收客户端发送的消息，需要给通道设置读的权限
                socketChannel.register(selector, SelectionKey.OP_READ);
            } else if (key.isReadable()) {
                //处理读的事件
                SocketChannel socketChannel = (SocketChannel) key.channel();
                ByteBuffer byteBuffer = ByteBuffer.allocate(1014);
                int read = socketChannel.read(byteBuffer);
                if (read > 0) {
                    String info = new String(byteBuffer.array(), "gbk").trim();
                    System.out.println("服务端收到数据" + info);
                } else {
                    System.out.println("未读到数据，关闭客户端");
                    key.cancel();
                }
            }
        }
    }
}
